#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
#include <signal.h>
#include "Task.hpp"
#include "log.hpp"
#include "threadpool.hpp"
#include "Init.hpp"
#include "guard.hpp"

Log lg;
Init it;
Guard gd;

const uint16_t default_port = 8888;
const std::string default_ip = "0.0.0.0";

const int backlog = 10;

enum
{
    SOCKET_ERR = 1,
    BIND_ERR,
    LISTEN_ERR
};

class TcpServer;

class ThreadData
{
public:
    ThreadData(const int &sockfd, TcpServer *tcp)
        : sockfd_(sockfd), tcp_(tcp)
    {
    }

public:
    int sockfd_;
    TcpServer *tcp_;
};

class TcpServer
{
public:
    TcpServer(const uint16_t &port = default_port, const std::string &ip = default_ip)
        : port_(port), ip_(ip), listensockfd_(-1)
    {
    }

    void Init()
    {
        // 1.创建socket
        listensockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listensockfd_ < 0)
        {
            lg(Fatal, "socket error, errno:%d, error string:%s", errno, strerror(errno));
            exit(SOCKET_ERR);
        }
        lg(Info, "socket success, errno:%d, listensockfd_:%d", errno, listensockfd_);

        int opt = 1;
        setsockopt(listensockfd_, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)); // 防止偶发性的服务器无法进行立即重启

        // 2.bind
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        local.sin_addr.s_addr = inet_addr(ip_.c_str());

        socklen_t len = sizeof(local);
        int n1 = bind(listensockfd_, (const struct sockaddr *)&local, len);
        if (n1 < 0)
        {
            lg(Fatal, "bind error, errno:%d, error string:%s", errno, strerror(errno));
            exit(BIND_ERR);
        }
        lg(Info, "bind success, errno:%d, listensockfd_:%d", errno, listensockfd_);

        // 3.监听
        int n2 = listen(listensockfd_, backlog);
        if (n2 < 0)
        {
            lg(Fatal, "listen error, errno:%d, error string:%s", errno, strerror(errno));
            exit(LISTEN_ERR);
        }
        lg(Info, "listen success, errno:%d, listensockfd_:%d", errno, listensockfd_);
    }

    void Service(const int &sockfd)
    {
        while (true)
        {
            char buffer[1024];
            int n = read(sockfd, buffer, sizeof(buffer) - 1);
            if (n < 0)
            {
                lg(Fatal, "read error");
                exit(1);
            }
            else if (n == 0)
            {
                lg(Info, "client quit， server close sockfd,sockfd:%d", sockfd);
                break;
            }
            buffer[n] = 0;
            cout << "client say# " << buffer << endl;

            string echo_message = "server echo@";
            echo_message += buffer;
            write(sockfd, echo_message.c_str(), echo_message.size());
        }
    }

    static void *Routine(void *args)
    {
        ThreadData *td = static_cast<ThreadData *>(args);
        pthread_detach(pthread_self());

        td->tcp_->Service(td->sockfd_);
        delete td;
    }

    void run()
    {
        //gd();                     // 守护进程化
        signal(SIGPIPE, SIG_IGN); // 忽略SIGPIPE信号 防止client关闭sockfd 系统会给server发送信号杀掉服务。

        lg(Info, "tcpserver is running...");
        ThreadPool<Task>::GetInstance()->strat();

        while (true)
        {
            // 4.获取新连接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);

            // accept会返回一个新的sockfd,这个新的sockfd与客户端进行连接并通信。而listensockfd_的作用是负责监听。
            int sockfd = accept(listensockfd_, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                lg(Fatal, "accept error, sockfd:%d,errno:%d, error string:%s", sockfd, errno, strerror(errno));
                continue;
            }

            uint16_t clientport = ntohs(client.sin_port);
            std::string clientip = inet_ntoa(client.sin_addr);

            lg(Info, "[%s]:[%d] get a new link... sockfd:%d", clientip.c_str(), clientport, sockfd);

            // 5.接收/发送消息

            // version 1 ---单进程版
            //  Service(sockfd);
            //  //走到这里代表通信客户端已经退出，准备获取新连接，需要关闭不要的文件描述符
            //  close(sockfd);

            // version 2 ---多进程版
            // pid_t pid = fork();
            // if (pid == 0)
            // {
            //     close(listensockfd_);
            //     // child
            //     if(fork()>0) exit(0);//子进程退出
            //     Service(sockfd);    //孙子进程
            // }

            // waitpid(-1,nullptr,0);
            // close(sockfd);

            // // version 3 ---多线程版
            // pthread_t tid;
            // ThreadData *td = new ThreadData(sockfd, this);
            // pthread_create(&tid, nullptr, Routine, td);

            // // version 4 ---线程池
            Task s(sockfd, clientip, clientport);
            ThreadPool<Task>::GetInstance()->push(s);
        }
    }

    ~TcpServer()
    {
        close(listensockfd_);
    }

private:
    int listensockfd_;
    uint16_t port_;
    std::string ip_;
};